//
//  JMFormSectionDescriptor.m
//  SYPerfectDemo
//
//  Created by Lssyyy on 2019/7/31.
//  Copyright © 2019年 Lssyyy. All rights reserved.
//

#import "JMFormSectionDescriptor.h"
#import "JMFormBaseCell.h"
#import "JMFormBaseViewController.h"
#import "UIView+JMFormAdditions.h"
@interface JMFormDescriptor (_JMFormSectionDescriptor)

@property (readonly) NSDictionary* allRowsByTag;

-(void)addRowToTagCollection:(JMFormRowDescriptor*)rowDescriptor;
-(void)removeRowFromTagCollection:(JMFormRowDescriptor*) rowDescriptor;
-(void)showFormSection:(JMFormSectionDescriptor*)formSection;
-(void)hideFormSection:(JMFormSectionDescriptor*)formSection;

-(void)addObserversOfObject:(id)sectionOrRow predicateType:(JMPredicateType)predicateType;
-(void)removeObserversOfObject:(id)sectionOrRow predicateType:(JMPredicateType)predicateType;

@end

@interface JMFormSectionDescriptor()

@property NSMutableArray * formRows;
@property NSMutableArray * allRows;
@property BOOL isDirtyHidePredicateCache;
@property (nonatomic) NSNumber* hidePredicateCache;

@end
@implementation JMFormSectionDescriptor

@synthesize hidden = _hidden;
-(void)dealloc
{
    [self.formDescriptor removeObserversOfObject:self predicateType:JMPredicateTypeHidden];
    @try {
        [self removeObserver:self forKeyPath:@"formRows"];
    }
    @catch (NSException * __unused exception) {}
}

#pragma mark - KVO

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if (!self.formDescriptor.delegate) return;
    if ([keyPath isEqualToString:@"formRows"]){
        if ([self.formDescriptor.formSections containsObject:self]){
            if ([[change objectForKey:NSKeyValueChangeKindKey] isEqualToNumber:@(NSKeyValueChangeInsertion)]){
                NSIndexSet * indexSet = [change objectForKey:NSKeyValueChangeIndexesKey];
                JMFormRowDescriptor * formRow = [((JMFormSectionDescriptor *)object).formRows objectAtIndex:indexSet.firstIndex];
                NSUInteger sectionIndex = [self.formDescriptor.formSections indexOfObject:object];
                [self.formDescriptor.delegate formRowHasBeenAdded:formRow atIndexPath:[NSIndexPath indexPathForRow:indexSet.firstIndex inSection:sectionIndex]];
            }
            else if ([[change objectForKey:NSKeyValueChangeKindKey] isEqualToNumber:@(NSKeyValueChangeRemoval)]){
                NSIndexSet * indexSet = [change objectForKey:NSKeyValueChangeIndexesKey];
                JMFormRowDescriptor * removedRow = [[change objectForKey:NSKeyValueChangeOldKey] objectAtIndex:0];
                NSUInteger sectionIndex = [self.formDescriptor.formSections indexOfObject:object];
                [self.formDescriptor.delegate formRowHasBeenRemoved:removedRow atIndexPath:[NSIndexPath indexPathForRow:indexSet.firstIndex inSection:sectionIndex]];
            }
        }
    }
}


-(instancetype)init
{
    self = [super init];
    if (self){
        _formRows = [NSMutableArray array];
        _allRows = [NSMutableArray array];
        _sectionInsertMode = JMFormSectionInsertModeLastRow;
        _sectionOptions = JMFormSectionOptionNone;
        _title = nil;
        _footerTitle = nil;
        _hidden = @NO;
        _hidePredicateCache = @NO;
        _isDirtyHidePredicateCache = YES;
        [self addObserver:self forKeyPath:@"formRows" options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld) context:0];
    }
    return self;
}

-(instancetype)initWithTitle:(NSString *)title sectionOptions:(JMFormSectionOptions)sectionOptions sectionInsertMode:(JMFormSectionInsertMode)sectionInsertMode{
    self = [self init];
    if (self){
        _sectionInsertMode = sectionInsertMode;
        _sectionOptions = sectionOptions;
        _title = title;
        if ([self canInsertUsingButton]){
            _multivaluedAddButton = [JMFormRowDescriptor formRowDescriptorWithTag:nil rowType:JMFormRowDescriptorTypeButton title:@"Add Item"];
            [_multivaluedAddButton.cellConfig setObject:@(NSTextAlignmentNatural) forKey:@"textLabel.textAlignment"];
            _multivaluedAddButton.action.formSelector = NSSelectorFromString(@"multivaluedInsertButtonTapped:");
            [self insertObject:_multivaluedAddButton inFormRowsAtIndex:0];
            [self insertObject:_multivaluedAddButton inAllRowsAtIndex:0];
        }
    }
    return self;
}
+(instancetype)formSection
{
    return [[self class] formSectionWithTitle:nil];
}

+(instancetype)formSectionWithTitle:(NSString *)title
{
    return [[self class] formSectionWithTitle:title sectionOptions:JMFormSectionOptionNone];
}
+(instancetype)formSectionWithTitle:(NSString *)title sectionOptions:(JMFormSectionOptions)sectionOptions
{
    return [[self class] formSectionWithTitle:title sectionOptions:sectionOptions sectionInsertMode:JMFormSectionInsertModeLastRow];
}

+(instancetype)formSectionWithTitle:(NSString *)title sectionOptions:(JMFormSectionOptions)sectionOptions sectionInsertMode:(JMFormSectionInsertMode)sectionInsertMode
{
    return [[[self class] alloc] initWithTitle:title sectionOptions:sectionOptions sectionInsertMode:sectionInsertMode];
}


-(void)addFormRow:(JMFormRowDescriptor *)formRow
{
    NSUInteger index;
    
    if ([self canInsertUsingButton]) {
        index = ([self.formRows count] > 0) ? [self.formRows count] - 1 : 0;
    } else {
        index = [self.allRows count];
    }
    
    [self insertObject:formRow inAllRowsAtIndex:index];
}
- (void)insertObject:(JMFormRowDescriptor *)formRow inFormRowsAtIndex:(NSUInteger)index
{
    formRow.sectionDescriptor = self;
    [self.formRows insertObject:formRow atIndex:index];
}
- (void)insertObject:(JMFormRowDescriptor *)row inAllRowsAtIndex:(NSUInteger)index
{
    row.sectionDescriptor = self;
    [self.formDescriptor addRowToTagCollection:row];
    [self.allRows insertObject:row atIndex:index];
    row.disabled = row.disabled;
    row.hidden = row.hidden;
}

- (void)removeObjectFromFormRowsAtIndex:(NSUInteger)index
{
    [self.formRows removeObjectAtIndex:index];
}

-(void)removeFormRowAtIndex:(NSUInteger)index
{
    if (self.formRows.count > index){
        JMFormRowDescriptor *formRow = [self.formRows objectAtIndex:index];
        NSUInteger allRowIndex = [self.allRows indexOfObject:formRow];
        [self removeObjectFromFormRowsAtIndex:index];
        [self removeObjectFromAllRowsAtIndex:allRowIndex];
    }
}

-(void)removeFormRow:(JMFormRowDescriptor *)formRow
{
    NSUInteger index = NSNotFound;
    if ((index = [self.formRows indexOfObject:formRow]) != NSNotFound){
        [self removeFormRowAtIndex:index];
    }
    else if ((index = [self.allRows indexOfObject:formRow]) != NSNotFound){
        if (self.allRows.count > index){
            [self removeObjectFromAllRowsAtIndex:index];
        }
    };
}

- (void)removeObjectFromAllRowsAtIndex:(NSUInteger)index
{
    JMFormRowDescriptor * row = [self.allRows objectAtIndex:index];
    [self.formDescriptor removeRowFromTagCollection:row];
    [self.formDescriptor removeObserversOfObject:row predicateType:JMPredicateTypeDisabled];
    [self.formDescriptor removeObserversOfObject:row predicateType:JMPredicateTypeHidden];
    [self.allRows removeObjectAtIndex:index];
}

#pragma mark - Helpers

-(BOOL)canInsertUsingButton
{
    return (self.sectionInsertMode == JMFormSectionInsertModeButton && self.sectionOptions & JMFormSectionOptionCanInsert);
}



-(BOOL)evaluateIsHidden
{
    if ([_hidden isKindOfClass:[NSPredicate class]]) {
        if (!self.formDescriptor) {
            self.isDirtyHidePredicateCache = YES;
        } else {
            @try {
                self.hidePredicateCache = @([_hidden evaluateWithObject:self substitutionVariables:self.formDescriptor.allRowsByTag ?: @{}]);
            }
            @catch (NSException *exception) {
                // predicate syntax error.
                self.isDirtyHidePredicateCache = YES;
            };
        }
    }
    else{
        self.hidePredicateCache = _hidden;
    }
    if ([self.hidePredicateCache boolValue]){
        if ([self.formDescriptor.delegate isKindOfClass:[JMFormBaseViewController class]]){
            JMFormBaseCell* firtResponder = (JMFormBaseCell*) [((JMFormBaseViewController*)self.formDescriptor.delegate).tableView findFirstResponder];
            if ([firtResponder isKindOfClass:[JMFormBaseCell class]] && firtResponder.rowDescriptor.sectionDescriptor == self){
                [firtResponder resignFirstResponder];
            }
        }
        [self.formDescriptor hideFormSection:self];
    }
    else{
        [self.formDescriptor showFormSection:self];
    }
    return [self.hidePredicateCache boolValue];
}

-(id)hidden
{
    return _hidden;
}

-(void)setHidden:(id)hidden
{
    if ([_hidden isKindOfClass:[NSPredicate class]]){
        [self.formDescriptor removeObserversOfObject:self predicateType:JMPredicateTypeHidden];
    }
//    _hidden = [hidden isKindOfClass:[NSString class]] ? [hidden formPredicate] : hidden;
    _hidden = hidden;
    if ([_hidden isKindOfClass:[NSPredicate class]]){
        [self.formDescriptor addObserversOfObject:self predicateType:JMPredicateTypeHidden];
    }
    [self evaluateIsHidden]; // check and update if this row should be hidden.
}

-(BOOL)isMultivaluedSection
{
    return (self.sectionOptions != JMFormSectionOptionNone);
}
@end
